package neuralNetwork;

import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.util.Arrays;

import beerAgent.BeerParameters;
import evolutionaryLoop.EvolutionaryParameters;
import evolutionaryLoop.selectionMechanisme.SigmaSelection;
import evolutionaryLoop.selectionProtocol.OverProduction;
import evolutionaryProblems.Problem;
import genotype.BeerGenotype;

public class CTRNNTest {

	private static CTRNN ctrnn;

	public static void main(String[] args) {
//		int[] nofNeuronsPerLayer = {3,2,6,1};
//		EvolutionaryParameters parameters = initialise(null); 
//		BeerGenotype genotype = new BeerGenotype(nofNeuronsPerLayer, parameters);
//		CTRNN ctrnn = new CTRNN(nofNeuronsPerLayer); 
//		ctrnn.setWeights(convertfuck(genotype.getArrayGenotype())); 
//		System.out.println(ctrnn);
//		test(); 
//		test2();
		avoidenceTest();
	}
	

	private static void avoidenceTest() {
		int[] neuronsPerLayer = {5,2,2}; 
//		double[] testWeights = {1.4512351289170176, 1.0739863605280164, 1.5625251264174533, 4.539915936742751, 1.4962162225167743, 1.2686536362768819, 1.6260237010975467, 1.0703374570280009, -2.1036904926094158, -4.154191930980975, -5.744394376973449, -0.04183044724289786, -0.9876748255374537, -4.6177824587622, -0.9698634748967239, 2.786857483494246, 1.1427747469172171, 0.6865212835812997, -3.809931502006364, 4.134183726329969, -2.3364755093577827, -4.597211183868031, -3.97602984351166, 3.0270869407068037, 0.8465175798637201, -1.2504200035447957, 0.08026332904066269, -2.751350902197238, -2.1846044059243064, -2.660442443773632, 3.9922427565926473, 0.957625068031116, 4.93644050287741, 0.11575022962315185}; 
		double[] testWeights = {2.722441484267576, 4.792472362648542, 1.4343111827828037, 1.9186663860770121, 1.0172304900506224, 1.255045004606803, 1.5451753515226523, 1.059324101832555, -1.7317390005883553, -6.53260236083125, -0.4807191439630927, -4.920602966299023, 0.9770674010125671, 2.521420633676307, 2.4589692629126834, 0.11569646247142096, 3.4127698874860712, -0.13143433000717852, -0.80255592183779, 2.244556503011866, -3.107748559219573, 3.4400432128885363, -3.651249376338476, 4.742605266013712, -4.943424288184445, -0.018163518626518105, 3.8966606242920303, -4.292455292508583, -1.9460649653262019, 1.7345174995425765, 1.1887423507107382, -1.1258706337303193, -0.12297276232485554, 4.705465015945023};
//		double[] testWeights = {1.1,1.2,1.3,1.4, 1.5,2,1,1.5, -5,0,-2,-8,    4,-4, 3,2, -2,-1, 4,4, 0,2,  -1,5,-3,-5,  1,2,0,-3,  4,3,  -2,4}; 
		boolean[] allTrueSensors = {true,true,true,true,true}; 
		boolean[] lockSensors = {false,false,true,false,false}; 
		boolean[] allFalseSensors = {false,false,false,false,false};
		boolean[] trueRight = {true,true,false,false,false};
		boolean[] trueRightMidle = {true,true,true,false,false}; 
		boolean[] trueLeft = {false,false,true,true,true};
		boolean[] trueOneRight = {false,false,false,false,true}; 
		boolean[] trueOneLeft = {true,false,false,false,false};
		boolean[] falseOneRight = {true,true,true,true,false}; 
		
		ctrnn = new CTRNN(neuronsPerLayer); 
		ctrnn.setWeights(testWeights); 
		System.out.println(Arrays.toString(testWeights)); 
		System.out.println(Arrays.toString(ctrnn.getWeights())); 
		System.out.println(ctrnn);
		System.out.println();
		
//		for (int i = 0; i < 8; i++) {
//			runInput(allFalseSensors);
//		}
		for (int i = 0; i < 5; i++) {
			runInput(trueOneLeft);
		}
//		runInput(trueRight); 
//		runInput(trueRight); 
//		runInput(trueRight); 
//		runInput(trueRight); 
		
		//Avoid large object
//		runInput(trueOneRight);
//		runInput(trueLeft);
//		runInput(allTrueSensors);
//		runInput(trueRight);
//		runInput(allFalseSensors); 
		
		//Catch small object
//		runInput(trueOneRight);
//		runInput(trueLeft);
//		runInput(trueRightMidle);
//		runInput(trueRightMidle); 
//		runInput(trueRightMidle); 
//		runInput(trueLeft);
//		runInput(allFalseSensors);
		
		
		
		runInput(falseOneRight);
		runInput(falseOneRight);
		runInput(falseOneRight);
		
		//runInput(trueRightMidle); runInput(trueRightMidle); 
	}
	
	public static void runInput(boolean[] input){
		System.out.println(Arrays.toString(input));
		double[]outputs = ctrnn.update(input);
		System.out.println(Arrays.toString(outputs) + " Move: " + getSteps(outputs)); 
		System.out.println(ctrnn.activationString());
		System.out.println();
	}
	
	public static int getSteps(double[] outputs) {
		double difference = outputs[0] - outputs[1]; 
		int steps = (int) (difference*5);
		return steps; 
	}


	public static double[] convertfuck(Double[] array){
		double[] newArray = new double[array.length]; 
		for (int i = 0; i < array.length; i++) {
			newArray[i] = array[i]; 
		}
		return newArray; 
	}
	
	
	public static EvolutionaryParameters initialise(Problem problem) {
		BeerParameters parameters = new BeerParameters();
		int[] nofNeuronsPerLayer = {3,2,6,1};
		
		parameters.setMaxNumberOfIterations(1000); 
		parameters.setMutationRate(0.05); 
		parameters.setCrossoverRate(0.9); 
		parameters.setNumOfChildenToBeGenerated(100); 
		parameters.setPopulationSize(100); 
		parameters.setElitims(1);
		parameters.setViewMap(false);
		parameters.setTimePerFrame(500);
		parameters.setNetworkLayout(nofNeuronsPerLayer);
		parameters.setCulling(0);
		parameters.setCrossoverPoints(1); 
		parameters.setAdultSelectionProtocol(new OverProduction(parameters)); 
		parameters.setParenetSelectionMechanism(new SigmaSelection()); 
		parameters.setMinGain(1.0);
		parameters.setMaxGain(1.0);
		parameters.setMinTimeCons(2.0);
		parameters.setMaxTimeCons(2.0);
		parameters.setMinBias(3.0);
		parameters.setMaxBias(3.0);
		parameters.setMinWeight(5.0);
		parameters.setMaxWeight(5.0);
		
		FileSystem fileSys = FileSystems.getDefault();
		String sep = fileSys.getSeparator();
		parameters.setWriteStatistics("OneMax" + sep + "Project1-Task3" + sep + "OneMax ");
		return parameters; 
	}
	
	public static void test(){
		int[] neuronsPerLayer = {5,2,2}; 
		double[] testWeights = {1,1,1,1, 1.5,2,1,1.5, -5,0,-2,-8,    4,-4, 3,2, -2,-1, 4,4, 0,2,  -1,5,-3,-5,  1,2,0,-3,  4,3,  -2,4}; 
		boolean[] testSensors = {false,false,true,true,false}; 
		CTRNN ctrnn = new CTRNN(neuronsPerLayer); 
		ctrnn.setWeights(testWeights); 
		
		System.out.println(ctrnn);
		System.out.println();
		
		System.out.println(ctrnn.activationString());
		System.out.println();
		
		System.out.println(Arrays.toString(ctrnn.update(testSensors))); 
		System.out.println(ctrnn.activationString());
		System.out.println();
		
		for (int i = 0; i < 1000; i++) {
			System.out.println(Arrays.toString(ctrnn.update(testSensors))); 
			System.out.println(ctrnn.activationString());
			System.out.println();
		}
	}

	private static void test2() {
		int[] neuronsPerLayer = {5,2,2}; 
		double[] testWeights = {1.1,1.2,1.3,1.4, 1.5,2,1,1.5, -5,0,-2,-8,    4,-4, 3,2, -2,-1, 4,4, 0,2,  -1,5,-3,-5,  1,2,0,-3,  4,3,  -2,4}; 
		boolean[] testSensors = {false,false,true,true,false}; 
		CTRNN ctrnn = new CTRNN(neuronsPerLayer); 
		ctrnn.setWeights(testWeights); 
		System.out.println(Arrays.toString(testWeights)); 
		System.out.println(Arrays.toString(ctrnn.getWeights())); 
		System.out.println(ctrnn);
	}
		
}
